﻿#include "declarationmanager.h"

#include <stdexcept>

#include <QDir>
#include <QFile>
#include <QDebug>

#include "datamodel.h"
#include "pugixml/pugixml.hpp"

DeclarationManager::DeclarationManager()
{

}

DeclarationManager::~DeclarationManager()
{
    this->destroyTypes ();
}

bool DeclarationManager::parseType(const std::string &definition_file, const std::string &type_name) const
{
    pugi::xml_document doc;
    if (!doc.load_file (definition_file.c_str (), pugi::parse_full))
        return false;
    const Node *node = BuildNodeTreeFromXml (doc.document_element ());
    auto result = this->m_node_map.insert (
                std::make_pair(type_name, node)
                );
    return result.second;
}

void DeclarationManager::destroyTypes()
{
    for (const auto &itr: m_node_map)
    {
        itr.second->Destory ();
    }
    m_node_map.clear ();
}

bool DeclarationManager::initDeclarationLibPath(const std::string &library_dir)
{
    this->destroyTypes ();
    this->m_type_lib = library_dir;
    return true;
}

const Node *DeclarationManager::findNodeDeclaration(const std::string &node_id) const
{
    static const std::string SUFFIX = ".def";

    if (m_node_map.find (node_id) != m_node_map.end ())
        return m_node_map.at (node_id);

    if (!this->parseType (this->m_type_lib + '/' + node_id + SUFFIX, node_id))
        return nullptr;

    return m_node_map.at (node_id);
}

bool DeclarationManager::validationXmlScript(const std::string &file_path, std::ostream &out_info)
{
    pugi::xml_document doc;
    auto load_ret = doc.load_file (file_path.c_str (), pugi::parse_full);
    if (!load_ret)
    {
        out_info << load_ret.description () << std::endl;
        return false;
    }

    std::string node_id = doc.first_child ().attribute ("schema").as_string ();
    if (node_id.empty ())
    {
        out_info << "Except schema attribute in declaration node!!" << std::endl;
        return false;
    }

    auto node_rule = this->findNodeDeclaration (node_id);
    if (!node_rule)
    {
        out_info << node_id << " is not defined, can not validation file: " << file_path << std::endl;
        return false;
    }

    ValidationXmlFileWithRule (doc.document_element (), node_rule, out_info);

    return true;
}

DeclarationManager &DeclarationManager::getInstance()
{
    static DeclarationManager s_inst;

    return s_inst;
}
